package com.iotechn.unimall.app.api.integralactivity;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.iotechn.unimall.biz.service.integral.IntegralBizService;
import com.iotechn.unimall.core.exception.AppServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.core.util.DateUtils;
import com.iotechn.unimall.core.util.wx.WeChatTempleConstants;
import com.iotechn.unimall.core.util.wx.WeChatTempleUtils;
import com.iotechn.unimall.data.component.CacheComponent;
import com.iotechn.unimall.data.domain.IntegralTaskDO;
import com.iotechn.unimall.data.domain.RewardLadderDO;
import com.iotechn.unimall.data.domain.UserDO;
import com.iotechn.unimall.data.domain.UserIntegralSigninDO;
import com.iotechn.unimall.data.dto.UserDTO;
import com.iotechn.unimall.data.dto.integralactivity.UserIntegralSigninDTO;
import com.iotechn.unimall.data.dto.sign.NoIntegralSigninDTO;
import com.iotechn.unimall.data.enums.IntegralSonType;
import com.iotechn.unimall.data.enums.SystemStatusType;
import com.iotechn.unimall.data.enums.sign.IsSignType;
import com.iotechn.unimall.data.mapper.*;
import com.iotechn.unimall.data.util.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by rize on 2019/7/14.
 */
@Service
public class SignIntegralServiceImpl implements SignIntegralService {
    private static final Logger logger = LoggerFactory.getLogger(SignIntegralServiceImpl.class);
    @Autowired
    private UserIntegralSigninMapper userIntegralSigninMapper;
    @Autowired
    private IntegralUserMapper integralUserMapper;
    @Autowired
    private IntegralTaskMapper integralTaskMapper;
    @Autowired
    private IntegralDetailMapper integralDetailMapper;
    @Autowired
    private CacheComponent cacheComponent;
    @Autowired
    private IntegralBizService integralBizService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RewardLadderMapper rewardLadderMapper;


    @Override
    public Boolean isSign(Long userId) throws ServiceException{
        UserDTO userDTO=SessionUtil.getUser();
        Integer count=userIntegralSigninMapper.isSign(userDTO.getId());
        if(count!=null && count.intValue()>0){
            return true;
        }else{
            return false;
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> sign(Long userId) throws ServiceException{
        Map<String,Object> map=new HashMap<String,Object>();
        UserDTO userDTO=SessionUtil.getUser();
        Integer count=userIntegralSigninMapper.isSign(userDTO.getId());
        if(count!=null && count.intValue()>0){
            //代表今天已经签到了
            throw new AppServiceException(ExceptionDefinition.INTEGRAL_TODAY_SINGED);
        }
        //最近一次签到记录
        UserIntegralSigninDO latelySign = userIntegralSigninMapper.latelySignData(userId);
        int differentDay = 0;
        int signintimes = 1;
        if(latelySign != null){
            differentDay = DateUtils.differentDaysByMillisecond(latelySign.getSigninTime(), new Date());
            signintimes = latelySign.getSignintimes() + 1;
        }
        //上次签到据今天超过一天  从1开始
        if(differentDay > 1){
            signintimes = 1;
        }
        //计算积分 （任务+阶梯）
        Integer integral = integralBizService.calculateSignIntegral(userId,signintimes);
        if(integralBizService.recordSign(userId,integral,signintimes)>0){
            //计算积分 + 记录积分流水
            integralBizService.addIntegral(userId,integral, IntegralSonType.SIGN.getCode(),IntegralSonType.SIGN.getMsg()+"奖励"+integral+"积分",0L);
            integralBizService.computeSignTimes(userId,signintimes);
            map.put("signtimes",signintimes);
            map.put("addIntegral",integral);
        }else{
            throw new AppServiceException(ExceptionDefinition.INTEGRAL_TODAY_SINGED);
        }
        return map;
    }


    @Override
    public Map<String,Object> getContinueSign(Long userId) throws ServiceException, ParseException {
        Map<String,Object> result = new ConcurrentHashMap<>();
        final String continueTimes = "continueTimes";//连签次数
        final String continueData = "continueData";//连签数据
        final String nosignData = "nosignData";//未签到的显示数据
        final String maxDayKey = "maxDay";
        final String todaySign = "todaySign";
        final String maxRewardLadder = "maxRewardLadder";
        //拼接7天的未签到数据
        List<IntegralTaskDO> integralTaskDOS = integralTaskMapper.selectList(new EntityWrapper<IntegralTaskDO>().like("integral_title", "签到"));
        IntegralTaskDO integralTaskDO = integralTaskDOS.get(0);
        Integer integral = integralTaskDO.getIntegral();//每次奖励
        // 最高连续天数
        RewardLadderDO rewardLadderDO = rewardLadderMapper.getRewardMaxDay(integralTaskDO.getId().intValue());
        Integer maxDay = rewardLadderDO.getImplementTimes();
        // 奖励阶梯数据
        List<RewardLadderDO> rewardLadderDOS = rewardLadderMapper.selectList(new EntityWrapper<RewardLadderDO>().eq("type", integralTaskDO.getId()).eq("status", SystemStatusType.ON.getCode()));
        Map<Integer, RewardLadderDO> rewardLadderMap = rewardLadderDOS.stream().collect(Collectors.toMap(RewardLadderDO::getImplementTimes, Function.identity(), (key1, key2) -> key2));
        // 未奖励数据
        List<NoIntegralSigninDTO> noSignList = new ArrayList<>();
        for(int i = 1;i <= maxDay;i++) {
            NoIntegralSigninDTO nois=new NoIntegralSigninDTO();
            nois.setDayIndex(i);
            RewardLadderDO mapValue = rewardLadderMap.get(i);
            if(mapValue != null){
                nois.setRewardIntegral(mapValue.getIntegral());
            }
            nois.setIntegral(integral);
            noSignList.add(nois);
        }

        List<UserIntegralSigninDO> uisList= new ArrayList<>();
        UserIntegralSigninDO userIntegralSigninDO = userIntegralSigninMapper.latelySignData(userId);
        if(userIntegralSigninDO == null){
            //上次签到截止当前超过一天
            result.put(todaySign,isSign(userId));
            result.put(continueTimes,0);
            result.put(continueData,uisList);
            result.put(nosignData,noSignList);
            result.put(maxDayKey,maxDay);
            result.put(maxRewardLadder,rewardLadderDOS.get(rewardLadderDOS.size() -1));
            return result;
        }
        Integer signintimes = userIntegralSigninDO.getSignintimes();
        Date now = new Date();
        //最近一次签到时间
        Date latelySigninTime = userIntegralSigninDO.getSigninTime();
        int differentDays = DateUtils.differentDaysByMillisecond(DateUtils.getZeroDate(latelySigninTime),DateUtils.getZeroDate(now));
        if(differentDays > 1){
            //上次签到截止当前超过一天
            result.put(todaySign,isSign(userId));
            result.put(continueTimes,0);
            result.put(continueData,uisList);
            result.put(nosignData,noSignList);
            result.put(maxDayKey,maxDay);
            result.put(maxRewardLadder,rewardLadderDOS.get(rewardLadderDOS.size() -1));
            return result;
        }
        //获取最近连续签到的数据
        Wrapper<UserIntegralSigninDO> wrapper = new EntityWrapper<>();
        wrapper.andNew();
        //设置连签天数
        Date firstSignDay = DateUtils.getBeforeSomeDaysDate(latelySigninTime, -1 * (signintimes - 1));
        latelySigninTime = DateUtils.getBeforeSomeDaysDate(latelySigninTime,1);
        List<String> everyDays = DateUtils.getEveryDays( firstSignDay, latelySigninTime);
        for(int i =0;i< everyDays.size();i++) {
            wrapper.between("signin_time",DateUtils.getDateByStr(everyDays.get(i),"yyyy-MM-dd"),DateUtils.getBeforeSomeDaysDate(DateUtils.getDateByStr(everyDays.get(i),"yyyy-MM-dd"),1));
            if(i < everyDays.size()-1){
                wrapper.or();
            }
        }
        wrapper.andNew();
        wrapper.eq("user_id",userId);
        wrapper.orderBy("signin_time",true);
        uisList = userIntegralSigninMapper.selectList(wrapper);
        List<UserIntegralSigninDTO> uisDTOList = new ArrayList<>();
        for (int i = 1 ; i<= uisList.size();i++){
            UserIntegralSigninDTO dto = new UserIntegralSigninDTO();
            UserIntegralSigninDO userIntegralSigninDO1 = uisList.get(i- 1);
            BeanUtils.copyProperties(userIntegralSigninDO1,dto);
            dto.setDayIndex(i);
            RewardLadderDO mapValue = rewardLadderMap.get(i);
            dto.setRewardIntegral(0);
            if(mapValue != null){
                dto.setRewardIntegral(mapValue.getIntegral());
            }
            uisDTOList.add(dto);
        }
        result.put(continueTimes,uisDTOList.size());
        result.put(continueData,uisDTOList);
        for(int i = 1;i<= uisList.size();i++){
            noSignList.remove(0);
        }
        result.put(nosignData,noSignList);
        result.put(maxDayKey,maxDay);
        result.put(todaySign,isSign(userId));
        result.put(maxRewardLadder,rewardLadderDOS.get(rewardLadderDOS.size() -1));
        return result;
    }


    @Override
    public Map<String, Object> getCurrMonthSignLog(String timeInfo,Long userId) throws ServiceException, ParseException {
        final String continueData = "continueData";//连签数据
        Date now =new Date();
        if(StringUtils.isNotEmpty(timeInfo)){
            now = DateUtils.getDateByStr(timeInfo,"yyyy-MM");
        }
        List<IntegralTaskDO> integralTaskDOS = integralTaskMapper.selectList(new EntityWrapper<IntegralTaskDO>().like("integral_title", "签到"));
        IntegralTaskDO integralTaskDO = integralTaskDOS.get(0);
        Integer integral = integralTaskDO.getIntegral();//每次奖励
        List<UserIntegralSigninDO> uisList= new ArrayList<>();
        Date monthStart = DateUtils.currMonthFirst(now, "yyyy-MM-dd hh:mm:ss");
        Date monthLast = DateUtils.currMonthLast(now, "yyyy-MM-dd hh:mm:ss");
        Wrapper<UserIntegralSigninDO> wrapper = new EntityWrapper<>();
        wrapper.ge("signin_time",monthStart);
        wrapper.le("signin_time",monthLast);
        wrapper.eq("user_id",userId);
        wrapper.orderBy("signin_time",true);
        uisList = userIntegralSigninMapper.selectList(wrapper);
        Map<Integer,UserIntegralSigninDO> signinDOMap = new HashMap<>();
        for ( UserIntegralSigninDO  userIntegralSigninDO: uisList
             ) {
            int dateDay = DateUtils.getDateDay(userIntegralSigninDO.getSigninTime());
            signinDOMap.put(dateDay,userIntegralSigninDO);
        }
        int daysOfMonth = DateUtils.getDaysOfMonth(now);
        // 未奖励数据
        List<NoIntegralSigninDTO> signList = new ArrayList<>();
        //获取本月1日星期   填补天数
        Date currMonthFirst = DateUtils.currMonthFirst(now, "yyyy-MM");
        int dayWeek = DateUtils.getDayWeek(currMonthFirst);
        for (int i = 0;i< dayWeek;i++){
            NoIntegralSigninDTO nois=new NoIntegralSigninDTO();
            nois.setIntegral(-1);
            nois.setDayIndex(-1);
            nois.setRewardIntegral(-1);
            nois.setType(-1);
            signList.add(nois);
        }
        for (int i = 1;i <= daysOfMonth; i++){
            NoIntegralSigninDTO nois=new NoIntegralSigninDTO();
            nois.setDayIndex(i);
            nois.setIntegral(integral);
            nois.setType(IsSignType.NOSIGN.getCode());
            UserIntegralSigninDO userIntegralSigninDO = signinDOMap.get(i);
            if(userIntegralSigninDO != null){
                nois.setIntegral(userIntegralSigninDO.getAddIntegral());
                nois.setType(IsSignType.SIGN.getCode());
            }
            signList.add(nois);
        }
        Map<String,Object> map = new HashMap<>();
        map.put(continueData,signList);
        return map;
    }


    public void signTemple(Long userId,Integer integral,Integer signintimes){
        UserDO userDO = userMapper.selectById(userId);
        String token ="";
        if(cacheComponent.hasKey(WeChatTempleUtils.getCacheToken(userId))){
            token = cacheComponent.getRaw(WeChatTempleUtils.getCacheToken(userId));
        }else{
            Map<String, Object> tokenMap = WeChatTempleUtils.getaccessToken();
            token = (String) tokenMap.get(WeChatTempleUtils.TOKENKEY);
            Integer second = (Integer) tokenMap.get(WeChatTempleUtils.EXPIRETIMEKEY);
            cacheComponent.putObj(WeChatTempleUtils.getCacheToken(userId),token,second);
        }
        Map<String,String> datas =new HashMap<>();
        datas.put("thing3","每日签到");
        datas.put("thing7","签到获得"+integral+"积分，已连续签到"+signintimes+"天，连续签到7天可领取额外积分奖励哦~");
        Map<String,String> sendData =new HashMap<>();
        sendData.put(WeChatTempleUtils.MK_TOUSER,userDO.getOpenId());
        sendData.put(WeChatTempleUtils.MK_TEMPLATE, WeChatTempleConstants.ACTIVITYMSG);
        sendData.put(WeChatTempleUtils.MK_PAGE,"");
        sendData.put(WeChatTempleUtils.MK_MINIPROGRAM,WeChatTempleUtils.pattern);
        Map<String, Object> newOrderTmp = WeChatTempleUtils.getNewOrderTmp(datas, sendData);
        try {
            String s = WeChatTempleUtils.sendTempleMsg(newOrderTmp, token);
            logger.info("模板消息返回"+ s);
            logger.info("签到赠送积分");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
